package com.qijian.flowable.common.listener;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.qijian.common.core.domain.BaseEntity;
import com.qijian.common.core.redis.RedisCache;
import com.qijian.common.enums.FlowableCommonEnum;
import com.qijian.common.enums.FlowableKeyEnum;
import com.qijian.common.utils.CommonUtil;
import com.qijian.common.utils.DateUtils;
import com.qijian.common.utils.StringUtils;
import com.qijian.common.utils.mybatis.WhereEntityTool;
import com.qijian.flowable.constant.FlowableConstant;
import com.qijian.flowable.domain.FlowableRecord;
import com.qijian.flowable.domain.FlowableRecordPower;
import com.qijian.flowable.domain.query.FlowableRecordPowerQuery;
import com.qijian.flowable.service.IFlowableRecordPowerService;
import com.qijian.flowable.service.IFlowableRecordService;
import com.qijian.flowable.service.IProcessDefinitionService;
import com.qijian.flowable.util.SpringContextUtils;
import com.qijian.tool.domain.Msg;
import com.qijian.tool.service.IMsgService;
import org.apache.commons.collections4.CollectionUtils;
import org.flowable.common.engine.api.delegate.event.FlowableEvent;
import org.flowable.common.engine.api.delegate.event.FlowableEventListener;
import org.flowable.common.engine.impl.event.FlowableEntityEventImpl;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.task.Comment;
import org.flowable.identitylink.api.IdentityLink;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.api.history.HistoricTaskInstanceQuery;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 任务节点前置监听处理类
 *
 * @author: qijian
 **/
@Component
public class TaskBeforeListener implements FlowableEventListener {

    // 用于发送消息的流程
    @Override
    public void onEvent(FlowableEvent event) {
        TaskEntity taskEntity = (TaskEntity) ((FlowableEntityEventImpl) event).getEntity();
        TaskService taskService = SpringContextUtils.getBean(TaskService.class);
        RedisCache redisCache = SpringContextUtils.getBean(RedisCache.class);
        RepositoryService repositoryService = SpringContextUtils.getBean(RepositoryService.class);
        HistoryService historyService = SpringContextUtils.getBean(HistoryService.class);
        if (taskEntity.getCategory() == null) {
            taskEntity.setCategory(FlowableConstant.CATEGORY_TODO);

            List<Comment> datas = taskService.getProcessInstanceComments(taskEntity.getProcessInstanceId());
            if (CollectionUtil.isNotEmpty(datas)) {
                if (!FlowableConstant.INITIATOR.equals(taskEntity.getTaskDefinitionKey())) {
                    IFlowableRecordService flowableRecordService = SpringContextUtils.getBean(IFlowableRecordService.class);
                    FlowableRecord record = new FlowableRecord();
                    record.setProcessInstanceId(taskEntity.getProcessInstanceId());
                    Comment component = datas.get(0);
                    record.setProcessContent(component.getFullMessage());
                    record.setExecutorId(Long.parseLong(component.getUserId()));
                    flowableRecordService.saveOrUpdate(record);
                }

                Comment component = datas.get(0);
                if (FlowableConstant.TH.equals(component.getType())) {
                    // 推送消息给退回人
                    HistoricTaskInstanceQuery query = historyService.createHistoricTaskInstanceQuery();
                    query.processInstanceId(taskEntity.getProcessInstanceId()).taskDefinitionKey(taskEntity.getTaskDefinitionKey());
                    // 历史任务处理人
                    HistoricTaskInstance instance = query.listPage(0, 1).get(0);
                    // 推送内容
//                  component.getFullMessage()

                    IFlowableRecordPowerService flowableRecordPowerService = SpringContextUtils.getBean(IFlowableRecordPowerService.class);
                    FlowableRecordPowerQuery criteria = new FlowableRecordPowerQuery();
                    criteria.setUserId(Long.parseLong(instance.getAssignee()));
                    criteria.setProcessIntaneId(taskEntity.getProcessInstanceId());
                    if (flowableRecordPowerService.count(WhereEntityTool.invoke(criteria)) == 0) {
                        FlowableRecordPower recordPower = new FlowableRecordPower();
                        recordPower.setProcessIntaneId(taskEntity.getProcessInstanceId());
                        recordPower.setType(component.getType());
                        recordPower.setUserId(Long.parseLong(instance.getAssignee()));
                        flowableRecordPowerService.save(recordPower);
                    }
                }
            }
            //发送消息（新增功能以后通过监听器发送消息）
            //获取流程实列（安全事故，安全奖励，安全惩罚）
            IProcessDefinitionService processDefinitionService = SpringContextUtils.getBean(IProcessDefinitionService.class);
            RuntimeService runtimeService = SpringContextUtils.getBean(RuntimeService.class);
            ProcessDefinition processDefinition = processDefinitionService.getProcessDefinitionById(taskEntity.getProcessDefinitionId());
            String activityId = null;
            if (processDefinition != null) {
                if (FlowableConstant.FLOWABLE_MSG_SENDER.contains(processDefinition.getName())) {
                    IMsgService msgService = SpringContextUtils.getBean(IMsgService.class);
                    Map<String, Object> variables = runtimeService.getVariables(taskEntity.getProcessInstanceId());
                    String code = variables.get("code") == null ? "" : variables.get("code").toString();
                    String userName = variables.get("userName") == null ? "" : variables.get("userName").toString();
                    String createTime = variables.get("createTime") == null ? "" : variables.get("createTime").toString();
                    String sourceId = null;
                    for (Map.Entry entry : variables.entrySet()) {
                        if (entry.getKey().toString().indexOf("input_") > -1) {
                            sourceId = entry.getValue().toString();
                            break;
                        }
                    }

                    List<IdentityLink> identityLinksForTask = taskService.getIdentityLinksForTask(taskEntity.getId());
                    if (CollectionUtil.isNotEmpty(datas)) {
                        Comment component = datas.get(0);
                        if (CollectionUtils.isEmpty(identityLinksForTask) && !FlowableConstant.TH.equals(component.getType()) && !FlowableConstant.CC.equals(component.getType())) {
                            return;
                        }
//                        if (component.getFullMessage().equals("自动审核")) {
//                            //判断是否有自动审核得人员（不发送消息）删除已发消息
//                            List<Msg> msgs = msgService.list(new LambdaQueryWrapper<Msg>().eq(
//                                    Msg::getSourceId, sourceId).eq(Msg::getUserId, component.getUserId()).orderByDesc(BaseEntity::getCreateTime));
//                            if (CollectionUtils.isNotEmpty(msgs)) {
//                                msgService.removeById(msgs.get(0).getId());
//                            }
//                            return;
//                        }

                    }

                    List<Msg> msgs = new ArrayList<>();
                    Set<String> userIds = identityLinksForTask.stream().filter(e -> StringUtils.isNotEmpty(e.getUserId())).map(n -> n.getUserId()).collect(Collectors.toSet());
                    if (CollectionUtil.isNotEmpty(datas)) {
                        Comment component = datas.get(0);
                        if (CollectionUtil.isNotEmpty(datas) && datas.size() > 1) {
                            List<Msg> msgs1 = msgService.list(new LambdaQueryWrapper<Msg>().eq(
                                    Msg::getSourceId, sourceId).eq(Msg::getUserId, component.getUserId()).orderByDesc(BaseEntity::getCreateTime));
                            if (CollectionUtils.isNotEmpty(msgs1)) {
                                if (userIds.contains(msgs1.get(0).getUserId().toString())) {
                                    return;
                                }
                            }
                        }
                        //退回消息到发送人，事故当事人
                        if (FlowableConstant.TH.equals(component.getType()) || (FlowableConstant.CC.equals(component.getType()) && datas.get(1).getType().equals(FlowableConstant.TH))) {
                            if (redisCache.getCacheObject("LC_" + sourceId) != null) {
                                return;
                            }
                            if (variables.get("title") != null) {
                                // todo
                                ArrayList<Long> userList1 = new ArrayList<>();
                                activityId = variables.get("activityId").toString();
                                List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery().processInstanceId(taskEntity.getProcessInstanceId()).list();
                                if (CollectionUtil.isNotEmpty(list)) {
                                    for (HistoricTaskInstance his : list) {
                                        if (his.getTaskDefinitionKey().equals(activityId)) {
                                            if (his.getAssignee() != null) {
                                                userList1.add(Long.parseLong(his.getAssignee()));
                                            }

                                        }
                                    }
                                }
                                userList1.add(Long.parseLong(variables.get("userId").toString()));
                                Set<Long> users = new HashSet(userList1);
                                for (Long u : users) {
                                    Msg msg = new Msg();
                                    msg.setSourceId(sourceId);
                                    msg.setSourceType(processDefinition.getKey());
                                    msg.setUserId(u);
                                    msg.setTitle("(退回)" + variables.get("title1").toString());
                                    msg.setCreateBy("admin");
                                    msg.setCreateByName(userName);
                                    msg.setOriginCreateDateTime(DateUtils.strToDate(createTime, DatePattern.NORM_DATETIME_PATTERN));
                                    msg.setContent("您收到一条退回" + processDefinition.getName() + "消息");
                                    Object mainFlowType = variables.get("mainFlowType");
                                    if(Objects.nonNull(mainFlowType)){
                                        if(StrUtil.equals(String.valueOf(mainFlowType), FlowableCommonEnum.flow_fin_finance_dispatch.getValue())){
                                            Object flowSourceId = variables.get("sourceId");
                                            msg.setUrl(FlowableKeyEnum.flowToValues(processDefinition.getKey()+"_t")+ CommonUtil.dealUrl(FlowableKeyEnum.flowToValues(processDefinition.getKey() + "_t")) +"id="+flowSourceId);
                                        }else if(StrUtil.equals(String.valueOf(mainFlowType), FlowableCommonEnum.flow_process_craft_dispatch.getValue())){
                                            Object flowSourceId = variables.get("sourceId");
                                            msg.setUrl(FlowableKeyEnum.flowToValues(processDefinition.getKey() + "_t") + CommonUtil.dealUrl(FlowableKeyEnum.flowToValues(processDefinition.getKey() + "_t")) + "id=" + flowSourceId);
                                        } else if (StrUtil.equals(String.valueOf(mainFlowType), FlowableCommonEnum.flow_process_performance.getValue())) {
                                            Object flowSourceId = variables.get("sourceId");
                                            msg.setUrl(FlowableKeyEnum.flowToValues(processDefinition.getKey() + "_t") + CommonUtil.dealUrl(FlowableKeyEnum.flowToValues(processDefinition.getKey() + "_t")) + "id=" + flowSourceId);
                                        } else if (StrUtil.equals(String.valueOf(mainFlowType), FlowableCommonEnum.flow_quality_craft_dispatch.getValue())) {
                                            Object flowSourceId = variables.get("sourceId");
                                            msg.setUrl(FlowableKeyEnum.flowToValues(processDefinition.getKey() + "_t") + CommonUtil.dealUrl(FlowableKeyEnum.flowToValues(processDefinition.getKey() + "_t")) + "id=" + flowSourceId);
                                        } else {
                                            msg.setUrl(FlowableKeyEnum.flowToValues(processDefinition.getKey() + "_t") + CommonUtil.dealUrl(FlowableKeyEnum.flowToValues(processDefinition.getKey() + "_t")) + "id=" + sourceId);
                                        }
                                    } else {
                                        msg.setUrl(FlowableKeyEnum.flowToValues(processDefinition.getKey() + "_t") + CommonUtil.dealUrl(FlowableKeyEnum.flowToValues(processDefinition.getKey() + "_t")) + "id=" + sourceId);
                                    }                                    msg.setProcessInstanceId(taskEntity.getProcessInstanceId());
                                    msgs.add(msg);
                                }
                                redisCache.setCacheObject("LC_" + sourceId, "已存在", 30, TimeUnit.SECONDS);
                            }
                        } else if (FlowableConstant.CC.equals(component.getType()) && !datas.get(1).getType().equals(FlowableConstant.TH)) {
                            if (redisCache.getCacheObject("LCCC_" + sourceId) != null) {
                                return;
                            }
                            List<Long> userList = new ArrayList<>();
                            String cc = (String) variables.get("cc");
                            if (StringUtils.isNotEmpty(cc)) {
                                List<String> ccList = Arrays.asList(cc.split(","));
                                if (CollectionUtils.isNotEmpty(ccList)) {
                                    userList.addAll(ccList.stream().map(e -> Long.parseLong(e)).collect(Collectors.toList()));
                                }
                                Set<Long> users = new HashSet(userList);
                                for (Long u : users) {
                                    Msg msg = new Msg();
                                    msg.setSourceId(sourceId);
                                    msg.setSourceType(processDefinition.getKey());
                                    msg.setUserId(u);
                                    msg.setTitle("(抄送)" + variables.get("title1").toString());
                                    msg.setCreateBy("admin");
                                    msg.setContent("您收到一条抄送" + processDefinition.getName() + "消息");
                                    Object mainFlowType = variables.get("mainFlowType");
                                    if(Objects.nonNull(mainFlowType)){
                                        if(StrUtil.equals(String.valueOf(mainFlowType), FlowableCommonEnum.flow_fin_finance_dispatch.getValue())){
                                            Object flowSourceId = variables.get("sourceId");
                                            msg.setUrl(FlowableKeyEnum.flowToValues(processDefinition.getKey() + "_t") + CommonUtil.dealUrl(FlowableKeyEnum.flowToValues(processDefinition.getKey() + "_t")) + "id=" + flowSourceId);
                                        }else if(StrUtil.equals(String.valueOf(mainFlowType), FlowableCommonEnum.flow_process_craft_dispatch.getValue())){
                                            Object flowSourceId = variables.get("sourceId");
                                            msg.setUrl(FlowableKeyEnum.flowToValues(processDefinition.getKey() + "_t") + CommonUtil.dealUrl(FlowableKeyEnum.flowToValues(processDefinition.getKey() + "_t")) + "id=" + flowSourceId);
                                        } else if (StrUtil.equals(String.valueOf(mainFlowType), FlowableCommonEnum.flow_quality_craft_dispatch.getValue())) {
                                            Object flowSourceId = variables.get("sourceId");
                                            msg.setUrl(FlowableKeyEnum.flowToValues(processDefinition.getKey() + "_t") + CommonUtil.dealUrl(FlowableKeyEnum.flowToValues(processDefinition.getKey() + "_t")) + "id=" + flowSourceId);
                                        } else {
                                            msg.setUrl(FlowableKeyEnum.flowToValues(processDefinition.getKey() + "_t") + CommonUtil.dealUrl(FlowableKeyEnum.flowToValues(processDefinition.getKey() + "_t")) + "id=" + sourceId);
                                        }
                                    } else {
                                        msg.setUrl(FlowableKeyEnum.flowToValues(processDefinition.getKey() + "_t") + CommonUtil.dealUrl(FlowableKeyEnum.flowToValues(processDefinition.getKey() + "_t")) + "id=" + sourceId);
                                    }
                                    msg.setOriginCreateDateTime(DateUtils.strToDate(createTime, DatePattern.NORM_DATETIME_PATTERN));
                                    msg.setCreateByName(userName);
                                    msg.setTaskId(null);
                                    msg.setProcessInstanceId(taskEntity.getProcessInstanceId());
                                    msgs.add(msg);
                                }
                                redisCache.setCacheObject("LCCC_" + sourceId, "已存在", 30, TimeUnit.SECONDS);
                                extracted(processDefinition, variables, sourceId, msgs, userIds, code, userName, taskEntity.getId(), taskEntity.getProcessInstanceId(), createTime);
                            }
                        } else {
                            extracted(processDefinition, variables, sourceId, msgs, userIds, code, userName, taskEntity.getId(), taskEntity.getProcessInstanceId(), createTime);
                        }
                    }
                    if (CollectionUtils.isNotEmpty(msgs)) {
                        msgService.saveBatch(msgs, true, true);
                    }

                }
            }
        }
    }

    /**
     * 发送消息
     *
     * @param processDefinition
     * @param variables
     * @param sourceId
     * @param msgs
     * @param userIds
     */
    private static void extracted(ProcessDefinition processDefinition, Map<String, Object> variables, String sourceId, List<Msg> msgs, Set<String> userIds, String code, String userName, String taskId, String processInstanceId, String createTime) {
        for (String u : userIds) {
            Msg msg = new Msg();
            msg.setSourceId(sourceId);
            msg.setSourceType(processDefinition.getKey());
            msg.setUserId(Long.valueOf(u));
            msg.setTitle(variables.get("title").toString());
            msg.setCreateBy("admin");
            msg.setContent("您收到一条新" + processDefinition.getName() + "消息");
            msg.setUrl(FlowableKeyEnum.flowToValues(processDefinition.getKey()) + "?processInstanceName=" + code);
            msg.setCreateByName(userName);
            msg.setOriginCreateDateTime(DateUtils.strToDate(createTime, DatePattern.NORM_DATETIME_PATTERN));
            msg.setTaskId(taskId);
            msg.setProcessInstanceId(processInstanceId);
            msgs.add(msg);
        }
    }

    /**
     * 该isFailOnException()方法确定onEvent(..)方法在调度事件时抛出异常时的行为。
     * 当false返回，异常被忽略。当true返回，异常不会被忽略
     *
     * @return /
     */
    @Override
    public boolean isFailOnException() {
        return true;
    }

    /**
     * 该isFireOnTransactionLifecycleEvent()方法确定此事件侦听器是在事件发生时立即触发,还是由getOnTransaction()方法确定的事务生命周期事件触发。
     * 支持的事务生命周期事件的值是：COMMITTED，ROLLED_BACK，COMMITTING，ROLLINGBACK。
     *
     * @return /
     */
    @Override
    public boolean isFireOnTransactionLifecycleEvent() {
        return false;
    }

    @Override
    public String getOnTransaction() {
        return null;
    }
}

